package controllers;

import java.util.Random;

import main.Game;
import map.Map;

import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.geom.Vector2f;

import constans.Flag;
import constans.Global;
import constans.Parametr;

import collision.CollisionSector;

import entity.Bullet;
import entity.Hero;
import entity.Unit;

public class ObjectController {

	PlayerController player;
	Hero hero;
	CollisionSector collisionSector[][];
	int unitAddingTime = Parametr.UAddingTime;
	int time = 0;
	
	public ObjectController(PlayerController player)
	{
		this.player = player;
		collisionSector = new CollisionSector[Global.MAP_SIZE_X/CollisionSector.size][Global.MAP_SIZE_Y/CollisionSector.size];
		hero = new Hero(new Vector2f(1000,1000));
		for(int i = 0 ; i < collisionSector.length; i++)
			for(int j = 0 ; j < collisionSector.length; j++)
			{
				collisionSector[i][j] = new CollisionSector(i,j);
				if(collisionSector[i][j].isOn(hero))
					collisionSector[i][j].addHero(hero);
			}		
		addUnit(new Unit(new Vector2f(800,800)));
		addUnit();
		addUnit();
		addUnit();
	}
	public void render(GameContainer container, Graphics g) throws SlickException
	{	
		for(CollisionSector c1[] : collisionSector)
			for(CollisionSector c2 : c1)
				c2.render(container, g);				
	}
	public void update(GameContainer container, int delta) throws SlickException
	{		
		for(int i = 0 ; i < collisionSector.length; i++)
			for(int j = 0 ; j < collisionSector.length; j++)
			{
				if(!collisionSector[i][j].isEmpty)
					collisionSector[i][j].update(container, delta);
				//move
				//hero			
				if(collisionSector[i][j].heroMoved)
					loop : for(int k = i-1 ; k <= i+1 ; k++)
						for(int l = j-1 ; l <= j+1 ; l++)
							if(isSectorAvailable(k,l))
								if(collisionSector[k][l].isOn(collisionSector[i][j].getMovedHero()))
								{
									collisionSector[k][l].addHero(collisionSector[i][j].getMovedHero());
									break loop;
								}
				//unit				
				for(Unit u : collisionSector[i][j].getMovedUnit())
					loop : for(int k = i-1 ; k <= i+1 ; k++)
						for(int l = j-1 ; l <= j+1 ; l++)
							if(isSectorAvailable(k,l))
								if(collisionSector[k][l].isOn(u))
								{
									collisionSector[k][l].addUnit(u);
									break loop;
								}

				//unit target
				if(collisionSector[i][j].isUnit)
					if(Math.random() > 0.9)
						collisionSector[i][j].setTarget(hero.position);
	
				//bullet
				for(Bullet b : collisionSector[i][j].getMovedBullet())
					loop : for(int k = i-1 ; k <= i+1 ; k++)
						for(int l = j-1 ; l <= j+1 ; l++)
							if(isSectorAvailable(k,l))
								if(collisionSector[k][l].isOn(b))
								{
									collisionSector[k][l].addBullet(b);
									break loop;
								}
				//collisions
					//bullet vs unit/hero

				for(Bullet b : collisionSector[i][j].getBullets())
					loop : for(int k = i-1 ; k <= i+1 ; k++)
						for(int l = j-1 ; l <= j+1 ; l++)
							if(isSectorAvailable(k,l))
							{
								//vs unit
								if(b.herosBullet)
								{
									if(collisionSector[k][l].isUnit)										
										for(Unit u : collisionSector[k][l].getUnits())
											if(b.position.distance(u.position) < (u.size/2 + b.size/2))
											{
												if(!b.isDetonated())
													collisionSector[k][l].takeDamage(u, b.getDamage());
												if(u.isDead())
													player.addExperience(1);
												collisionSector[i][j].detonate(b);
												break loop;
											}
								}

								//vs hero
								else
									if(collisionSector[k][l].isHero)										
										if(b.position.distance(hero.position) < (hero.size/2 + b.size/2))
										{
											if(!b.isDetonated())
												hero.takeDamage(b.getDamage());
											collisionSector[i][j].detonate(b);
											break loop;
										}
							}
			}			
		addUnit();
		if(hero.getActLife() < 0) 
			Game.setState(Flag.theEndState, player.getTotalExperience());
	}	
	private void addUnit()
	{
		time++;
		if(time > unitAddingTime)
		{
			Random r = new Random();
			
			Vector2f u;
			do
			{
				u = new Vector2f(r.nextInt(Global.MAP_SIZE_X),r.nextInt(Global.MAP_SIZE_X));
			}
			while(isSoClose(u));
			addUnit(new Unit(u));
			
			if(unitAddingTime > Parametr.UMinAddingTime)
				unitAddingTime--;
			
			time = 0;
		}
	}
	private boolean isSoClose(Vector2f u)
	{
		if(u.distance(hero.position) < 500)
			return true;
		return false;
	}
	private boolean isSectorAvailable(int i, int j)
	{
		if( i >= 0)
			if(j >= 0)
				if( i < Global.MAP_SIZE_X/CollisionSector.size)
					if(j < Global.MAP_SIZE_Y/CollisionSector.size)
						return true;
		return false;
	}
	private void addUnit(Unit u)
	{
		for(int i = 0 ; i < collisionSector.length; i++)
			for(int j = 0 ; j < collisionSector.length; j++)
				if(collisionSector[i][j].isOn(u))
				{
					collisionSector[i][j].addUnit(u);
					return;
				}
	}
	public void addSkill(int flag)
	{
		switch(flag)
		{
			case Flag.attackSpeedButton:
				hero.addAttackSpeed();
				break;
			case Flag.damageButton:
				hero.addDamage();
				break;
			case Flag.speedButton:	
				hero.addSpeed();
				break;
			case Flag.accuracyButton:
				hero.addAttackAccuracy();
				break;		
			case Flag.maxLifeButton:
				hero.addMaxLife();
				break;
			case Flag.regenerationButton:
				hero.addRegeneration();
				break;			
				
		}
	}
	public float getLife()
	{
		return hero.getLife();
	}
	public float getDamage()
	{
		return hero.getDamage();
	}
	public float getAttackSpeed()
	{
		return hero.getAttackSpeed();
	}
	public float getAttackAccuracy()
	{
		return hero.getAttackAccuracy();
	}
	public float getRegeneration()
	{
		return hero.getRegenerationSpeed();
	}
	public float getMaxLife()
	{
		return hero.getMaxLife();
	}
	public float getSpeed()
	{
		return hero.getSpeed();
	}
	public float getActLife()
	{
		return hero.getActLife();
	}	
}




